如何处理TypeScript中的可选项和Undefined

您所在的位置:网站首页 typescript omit多个属性 如何处理TypeScript中的可选项和Undefined

如何处理TypeScript中的可选项和Undefined

2023-09-15 14:30| 来源: 网络整理| 查看: 265

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情。

原文链接:spin.atomicobject.com/2022/03/28/…

作者:MATTIE BEHRENS

正文从这里开始~

和JavaScript打交道就意味着和undefined打交道。如果一直留意这个问题,会让我们的大脑崩溃。然而,不注意的话就会在程序中引入bug。谢天谢地,TypeScript是一款很好用的工具,来帮助你处理此类问题,并且写出更健壮的代码。

什么是undefined?

在项目中设置TypeScript的严格模式,将会检查代码中的所有潜在问题。我建议你尽可能的让TypeScript更为严格(strict)。

undefined通常会出现在几个关键地方:

对象中未初始化或者不存在的属性 函数中被忽略的可选参数 用来表明请求值丢失的返回值 可能未被初始化的变量

TypeScript拥有处理上述所有问题的工具。

告诉TypeScript属性是否是可选

使用JavaScript进行编程,肯定遇到过undefined is not a function此类错误。

当你对一个对象访问并不存在的属性时,JavaScript将会返回undefined,而不是报错。

在TypeScript严格模式下,这意味着下面几种情况。首先,如果你不告诉TypeScript一个属性是可选的,TypeScript会期望这个值被显式设置。

type Foo = { bar: number; } const a: Foo = {}; // This is an error: // Property 'bar' is missing in type '{}' but required in type 'Foo'. // ts(2741) const b: Foo = { bar: 11 } // This works!;

在类型、接口或类的定义中,在属性名称中添加?将会把该属性标记为可选的。

type Foo = { bar?: number; } const a: Foo = {}; // This is now OK! const b: Foo = { bar: 11 }; // This is still OK. const c: Foo = { bar: undefined }; // This is also OK, somehow…?

上面示例中c的情况很有趣。如果你在IDE中把鼠标悬停在Foo上,你会看到TypeScript实际上已经把bar定义为number | undefined的联合类型。

尽管a和c是不同的对象,但是访问a.bar和c.bar的结果是相同的,都是undefined。

它是可选的。现在怎么办?

当然,当你遇到可选属性时,TypeScript会强制你去处理它。

type Foo = { bar?: number; } function addOne(foo: Foo): number { return foo.bar + 1; // This is an error: // Object is possibly 'undefined'. ts(2532) }

有好几种办法去解决这个问题。但最好的解决方式,与在JavaScript中的解决方式相同:检查你获取的值是否是你所期望的。

TypeScript可以理解这类检查,并可以使用它们来收窄对特定代码类型的检查范围(类型收窄)。

我们可以对bar属性使用 typeof, 用来检查它是否是undefined。

function addOne(foo: Foo): number { if (typeof foo.bar !== 'undefined') { return foo.bar + 1; } throw new Error('bar is undefined'); }

这种类型检查,不仅支持上面提到的a对象,其中a对象没有bar属性。而且也支持c对象,用来表明bar属性是undefined 。

TypeScript也会注意这段代码。在if子句中,会把bar属性的类型收窄为number。

TypeScript也会让你使用真值检查来“逃离”,就像这样:

function addOne(foo: Foo): number { if (foo.bar) { return foo.bar + 1; } throw new Error('bar is undefined'); }

需要注意的是,这段代码有一个很隐蔽的bug,那就是0是假值(falsy)。如果你传值为{ foo: 0 } ,这段代码就会抛出异常。

函数和方法可以具有可选参数

函数和方法可以具有可选参数,正如类型、接口和类也可以具有可选参数一样。函数和方法的可选参数也使用?进行标记:

function add(a: number, b?: number): number { … }

在这种情况下,我们实际上没有太多的内容来讨论如何处理b参数。因为如果不是由调用者来提供,它将是undefined。而它的类型是number | undefined ,正如我们的可选属性一样。所以我们可以使用同样的类型守卫来处理它。

我稍微更改了一下代码流程,用来说明TypeScript的流程控制分析是相当灵活的。

function add(a: number, b?: number): number { if (typeof b === 'undefined') return a; return a + b; } 缺少某样东西时的返回值

undefined也可以从一些核心语言的调用中返回。严格的TypeScript会发现这里潜在的bug。

function hello(who: string): string { return 'Hello, ' + who; } function helloStartingWith(letter: string): string { const people = ['Alice', 'Bob', 'Carol']; const person = people.find(name => name.startsWith(letter)); return hello(person); // This is the error: // Argument of type 'string | undefined' is not assignable to // parameter of type 'string'. // Type 'undefined' is not assignable to type 'string'.ts(2345) }

现在的问题是,person变量的类型不是string,而是string | undefined 的联合类型。这是因为Array.prototype.find 在没有找到指定值的情况下会返回undefined。

使用可选链

在现代TypeScript中(当然也包括现代JavaScript),有一些优雅的功能,可以让你的生活更加轻松。假设你有一个较为复杂的类型:

type Foo = { bar?: Bar } type Bar = { baz?: Baz } type Baz = { qux?: number }

当嵌套不深时,我们可以使用typeof来进行检查。但是看看下面的表达式:

foo.bar?.baz?.qux

可以肯定的是,它是number或者undefined 。如果bar、baz或qux中的任何一个缺失或未定义,它的最终结果将是后者undefined 。如果在所有属性都存在的情况下抵达表达式的末尾,最终结果将是qux的number类型的值。

这被称为可选链。当可选链遇到undefined或者null时,就会停止求值。

实话实说,这个例子有点刻意为之。但是在JavaScript框架中,对可能尚未初始化的变量进行属性访问是很常见的。或是在编写lambda表达式时,代码会被类型守卫弄得很臃肿。可选链?. 简直就是简化代码的神器。

断言的存在

当谈论到类时,TypeScript的分析可以标记那些没有显式初始化的属性,这可以为你省去一些麻烦。如果你正在使用的框架在代码运行之前,要确保你对这些属性进行设置,那么它也会产生一些麻烦。

虽然你可以把这些属性用?设置为可选的,从而使编译器满意。但你也会因为不得不写类型保护,从而使自己不满意。

如果你确定这些属性肯定会被设置,那么你可以使用! 来进行断言。TypeScript会认为你知道你在说些什么。

class Foo { bar!: number; // This is OK, but baz: number; // This isn't: // Property 'baz' has no initializer and is not definitely // assigned in the constructor. ts(2564) } 处理可选性

你别无选择,只能在JavaScript中处理可选性和未定义的问题。但好消息是,有很多工具可以用来处理它们。TypeScript使我的JavaScript代码变得比以前更加健壮,而且该语言的持续发展使一切变得更好。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3